BIO/NIO/AIO 三者关系解析
概述
在 Java 的 I/O 体系架构中,存在三种截然不同的 I/O 模型,分别为 BIO(Block I/O,阻塞型 I/O)、NIO(New I/O,非阻塞型 I/O)以及 AIO(Asynchronous I/O,异步 I/O)。
下面分析将从基本的术语开始讲解,最后归整讲述不同 I/O 模型的区别。
同步与异步
同步与异步关注的是消息通信机制。
- 同步是指发送方发出一个 I/O 请求时,在没有得到结果之前,该请求不返回结果。但是一旦请求返回时,就得到了相应的返回值。
- 异步是指发送方发出一个 I/O 请求之后,这个请求便立即返回,该请求没有返回结果。直至请求接收方(即被调用者)通过回调的方式来通知发送方,或者发送方主动询问接收方请求结果。
举个例子:
晚上我们需要去饭店预定位置,我们会优先打个电话给酒店来预定位置,当我们被告知饭店位置爆满时需要等待时。在同步的通信机制情况下,我们(发送方)只能默默地够保持通话的方式等待饭店(接收方)来通知我们空余位置的结果,不能够做别的事情。
而在异步的通信机制情况下,饭店(接收方)提供了特殊的服务,让我们(发送方)预留手机号码(回调方式),等有位置了可以主动通知你,我们就能够单方面切断通信,等待饭店通过我们预留的手机号码来通知我们,或者我们来主动询问饭店位置的空余情况。
阻塞与非阻塞
阻塞与非阻塞关注的是程序在等待调用结果时的状态。
- 阻塞是指请求结果返回之前,当前线程会被挂起。请求线程只有在得到结果之后才会返回。此时的线程处于阻塞状态,相当于卡住不动了。
- 非阻塞是指请求结果返回之前,当前线程不会被阻塞,可以处理别的任务。
同举以上的例子:
当我们打电话给饭店,被告知饭店位置爆满时需要等待时。在阻塞线程的请求方式下,我们(发送方)只能够保持通讯(阻塞),直至饭店(接收方)通知我们空余位置的结果。
而在非阻塞线程的请求方式下,我们(发送方)可以单方面挂掉电话,继续去逛街(非阻塞),直至饭店(接收方)通知我们,亦或者我们主动打电话去询问。
同步/异步与阻塞/非阻塞的区别
在以上的解释当中,同步/异步与阻塞/非阻塞两者之间的关系十分相似,但是它们却存在本质上的区别。
- 同步/异步注重的是消息的通信机制,重点在于消息本身。
- 阻塞/非阻塞注重的是程序在等待调用结果时的状态,重点在于程序本身。
BIO
BIO(Block I/O)为同步阻塞型 I/O。在服务器端中实现模式为一个连接一个线程,即客户端有连接请求时,服务器端就会按需启动一个线程来处理。
如果这个连接不做任何事情时,就造成不必要的线程开销,此时可以通过线程池机制来对于空线程进行回收,但是对于线程的创建与销毁等操作,系统所消耗的资源依然很大。
NIO
NIO(New I/O)为同步非阻塞型 I/O。在服务器端中实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上(Selector),多路复用器轮询到连接有 I/O 请求(Channel)才启动一个线程(Handler)来处理。用户进程也需要时不时地询问 I/O 操作是否就绪。
在 NIO 的 I/O 模型上,可以仅通过单线程的方式来处理高并发问题。
AIO
AIO(Asynchronous I/O)为异步非阻塞型 I/O。在此种模式下,用户进程只需要发起一个IO操作然后便立即返回,待 I/O 操作真正的完成以后,应用程序会得到I/O操作完成的通知,此时用户进程只需要对数据进行处理就好了,不需要进行实际的 I/O 读写操作,因为真正的 I/O 读取或者写入操作已经由内核完成了。
参考资料: